package org.streets.context.internal;

import static org.streets.context.HiveConstants.APPLICATION_CHARSET;
import static org.streets.context.HiveConstants.APPLICATION_COPYRIGHT;
import static org.streets.context.HiveConstants.APPLICATION_NAME;
import static org.streets.context.HiveConstants.APPLICATION_VENDOR;
import static org.streets.context.HiveConstants.APPLICATION_VERSION;

import java.io.File;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tapestry5.ioc.IOCUtilities;
import org.apache.tapestry5.ioc.RegistryBuilder;
import org.apache.tapestry5.ioc.services.ServiceActivity;
import org.apache.tapestry5.ioc.services.ServiceActivityScoreboard;
import org.apache.tapestry5.ioc.services.Status;
import org.streets.commons.util.DateFormatUtils;
import org.streets.context.HiveContext;
import org.streets.context.HiveContextException;
import org.streets.context.HiveContextModule;
import org.streets.context.HiveRegistry;
import org.streets.context.definition.ContextDefinition;

/**
 * Application configuration
 *
 * @author dzb
 *
 */
public final class HiveContextImpl implements HiveContext {

	public static final Log LOGGER = LogFactory.getLog(HiveContextImpl.class);
		
    private final String _name;
	private final String _root; //application root --> web dir
	
	private transient List<String> _modules = new ArrayList<String>(); 	
    private transient RegistryHolder _registry = null;
	
    public HiveContextImpl() {
    	_name = "STREETS V2 POWERED APPLICATION";
    	try {
			_root = new File(HiveContextImpl.class.getResource("/").toURI()).getAbsolutePath();
		} catch (URISyntaxException e) {		
			throw new HiveContextException("Can not context home path");
		}
    }
    /**
     * 
     * @param name Context名称
     */
    public HiveContextImpl(String name) {
    	_name = name;
    	try {
			_root = new File(HiveContextImpl.class.getResource("/").toURI()).getAbsolutePath();
		} catch (URISyntaxException e) {		
			throw new HiveContextException("Can not context home path");
		}
    }
	/**
	 * 
	 * @param name Context名称
	 * @param root Context的启动根目录
	 */
    public HiveContextImpl(String name, String root) {        
        _name = name;
        _root = root;
    }
	
    public String name() {
        return _name;
    }

    public String root() {
	return _root;
    }
	
	public HiveContext registerModules(Class<?>... moduleClasses) {
		for (Class<?> m_class : moduleClasses) {
			_modules.add(m_class.getName());
			LOGGER.info("-> Hive Module builder class: "+moduleClasses+" reigistered");
		}
		return this;
	}

	public HiveContext registerModules(String... moduleClassNames) {
		for (String m_class : moduleClassNames) {
			_modules.add(m_class);
			LOGGER.info("-> Hive Module builder class: "+moduleClassNames+" reigistered");
		}
		return this;
	}
	
	/**
	 * Startup HiveContext for use
	 */
	public void startup() {
		
		LOGGER.info("-> HiveContext [" + name() + "] startup on root: " + root() + "\n");		
		LOGGER.info("-> HiveContext startup at "+DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd hh:mm:ss") );
		
		synchronized (_root) {
			//创建 tapestry ioc
	        RegistryBuilder t_registry_builder = new RegistryBuilder();
	        //Add tapestry default module
	        IOCUtilities.addDefaultModules(t_registry_builder);
	        //Main Streets Module
	        t_registry_builder.add(HiveContextModule.class);

			for (String clzzName : _modules)  {
				t_registry_builder.add(clzzName);
			}
			// Create IoC container portal
			_registry = new RegistryHolder(t_registry_builder.build());
			// Initialize Context Symbols
			ContextSymbolProvider contextSymbol = _registry.service(ContextSymbolProvider.class);
			contextSymbol._init_(_root);
			// Here we must refresh all module definition in hivecontext
			// for get all module meta information
			ContextDefinition definition = _registry.service(ContextDefinition.class);
			definition._init_(t_registry_builder.getModuleDefs());
			// call all eager startup services marked with EagerLoad
			_registry.startup();
		}
		
		LOGGER.info("-> Finished build Registry at "+DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd hh:mm:ss"));		
    }
	
	/**
	 * 获取IoC容器的Registry对象
	 */
	public HiveRegistry registry() {
		if (_registry == null) {
			throw new HiveContextException("HiveContext["+name()+"] is not startup on "+root()+" yet. startup first.");
		}
		return _registry;
	}	
	/**
	 * Shutdown whole HiveContext 
	 */
	public void shutdown() {
		LOGGER.info("-> HiveContext shutdown at "+DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd hh:mm:ss") );
		LOGGER.info("-> HiveContext ["+name()+"] shutdown ....");
		_registry.shutdown();
		_modules.clear();	
		_registry = null;
		LOGGER.info("-> HiveContext ["+name()+"] shutdown successfully");
	}
	
	public void announce() {
        
	String charset 		= _registry.symbolValue(APPLICATION_CHARSET);
        String appname 		= _registry.symbolValue(APPLICATION_NAME);
        String version 		= _registry.symbolValue(APPLICATION_VERSION);
        String vendor 		= _registry.symbolValue(APPLICATION_VENDOR);
        String copyright 	= _registry.symbolValue(APPLICATION_COPYRIGHT);
        
        StringBuilder buffer = new StringBuilder("-> Startup status:\n\n");
        Formatter f = new Formatter(buffer);		 
        f.format("==========================================\n"+
        		 "  %s \n  version %s \n  charset '%s'\n  %s  "+ copyright +"\n"+
        		 "==========================================\n\n" +
                //" %,d ms overall.\n\n" +
                "Startup services status:\n",
                appname,
                version,
                charset,
                vendor);

        int unrealized = 0;

        ServiceActivityScoreboard scoreboard = _registry.service(ServiceActivityScoreboard.class);
        List<ServiceActivity> serviceActivity = scoreboard.getServiceActivity();

        int longest = 0;
        // One pass to find the longest name, and to count the unrealized services.
        for (ServiceActivity activity : serviceActivity) {        	
            Status status = activity.getStatus();
            longest = Math.max(longest, activity.getServiceId().length());
            if (status == Status.DEFINED || status == Status.VIRTUAL) unrealized++;
        }

        String formatString = "%" + longest + "s: %s\n";

        // A second pass to output all the services
        for (ServiceActivity activity : serviceActivity) {        	
            f.format(formatString, activity.getServiceId(), activity.getStatus().name());
        }

        f.format("\n%4.2f%% unrealized services (%d/%d)\n", 100. * unrealized / serviceActivity.size(), unrealized,
                 serviceActivity.size());

        LOGGER.info(buffer.toString());
	}
}
